package com.sunyard.utils.sm2;


import com.sunyard.utils.alipayutil.AliPayUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.FileInputStream;
import java.math.BigInteger;


/**
 * @ClassName: CertUtil
 * @Description: acpsdk证书工具类，主要用于对证书的加载和使用
 * @date 2016-7-22 下午2:46:20
 */
@Component
public class CertUtilSM2 {
    /**
     * sm2秘钥路径
     */
    @Value("${sm2.pri.cert.path}")
    private static String sm2PriCertPath;
    /**
     * sm2秘钥路径
     */
    @Value("${sm2.pri.cert.pwd}")
    private static String sm2PriCertPwd;

    /**
     * sm2公钥秘钥路径
     */
    @Value("${sm2.pub.cert.path}")
    private static String sm2PubCertPath;

    /**
     * 证书容器，存储对商户请求报文签名私钥证书.
     */
    private static BigInteger priKey = null;

    private static String certId = null;

    /**
     * 敏感信息加密公钥证书
     */
    private static X509Cert_SM2 encryptCert = null;

    // 根证书
    private static X509Cert_SM2 rootCert = null;

    public static String sm2PriKey = null;

    public static String sm2PubKey = null;

    static {
        init();
    }

    /**
     * 初始化所有证书.
     */
    public static void init() {
        try {
            //initSignCert();//初始化签名私钥证书
            //initVerifyCert();//初始化加密公钥
            //initRootCert();
        } catch (Exception e) {
            AliPayUtil.getLogger().warn("init失败。（如果是用对称密钥签名的可无视此异常。）", e);
        }
    }

    /**
     * 用配置文件acp_sdk.properties中配置的私钥路径和密码 加载签名证书
     */
    private static void initSignCert() throws Exception {

//		SDKConfig.getConfig();
//        if (SDKConfig.getByKey(SDKConfig.SM2_PRI_CERT_PATH) == null
//				|| SDKConfig.getByKey(SDKConfig.SM2_PRI_CERT_PWD)== null) {
//		    AliPayUtil.getLogger().warn("WARN: 加载国密证书失败， 停止加载签名证书。");
//			return;
//		}

        if (priKey != null) {
            priKey = null;
        }

        byte[] arrayOfByte = getSM2File(sm2PriCertPath);

        PKCS12_SM2 P12 = new PKCS12_SM2(arrayOfByte);

        // 签名私钥
        priKey = P12.getPrivateKey(sm2PriCertPwd);

        System.out.println("私钥(16进制)：" + priKey.toString(16));
        System.out.println("私钥(10进制)：" + priKey);
        sm2PriKey = priKey.toString(10);
        System.out.println("sm2PriKey：" + sm2PriKey);
        X509Cert_SM2 cert = P12.getPublicCert()[0];

        // 签名certId
        String tenCertId = cert.getCert().getSerialNumber().toString();

        BigInteger nb = new BigInteger(tenCertId, 10);
        certId = nb.toString(16);
        System.out.println("certId：" + certId);
    }

    /**
     * 读取SM2文件
     *
     * @param filePath
     * @return
     * @throws Exception
     */
    public static byte[] getSM2File(String filePath) throws Exception {

        FileInputStream crls = new FileInputStream(filePath);

        byte[] out = new byte[crls.available()];
        byte[] buffer = new byte[65536];

        int offset = 0;
        int rLength;

        while ((rLength = crls.read(buffer, 0, buffer.length)) != -1) {
            System.arraycopy(buffer, 0, out, offset, rLength);
            offset += rLength;
        }

        byte[] arrayOfByte1 = out;

        crls.close();

        return arrayOfByte1;
    }

    /**
     * 取得私钥
     *
     * @param encoding
     * @param password
     * @return
     * @throws Exception
     */
    public static BigInteger getPrivateKey() {
        return priKey;
    }

    /**
     * 取得证书Id
     *
     * @return
     */
    public static String getCertId() {
        return certId;
    }

    /**
     * 取得加密公钥
     *
     * @return
     */
    public static byte[] getEncryptPubKey() {
        return encryptCert.getPublicKey();
    }

    /**
     * 取得根证书
     *
     * @return
     */
    public static X509Cert_SM2 getEncryptCert() {
        return encryptCert;
    }

    /**
     * 取得根证书
     *
     * @return
     */
    public static X509Cert_SM2 getRootCert() {
        return rootCert;
    }

    /**
     * 用配置文件acp_sdk.properties配置路径 加载银联公钥加密证书
     */
    private static void initVerifyCert() throws Exception {
        System.out.println("加载敏感信息加密证书==>" + sm2PubCertPath);
        if (!StringUtil.isEmpty((sm2PubCertPath))) {

            encryptCert = new X509Cert_SM2(sm2PubCertPath);

            System.out.println("SM2 pubKey: " + encryptCert.getPubKey().toString());

            SM2PublicKey sm2pubkey = (SM2PublicKey) (encryptCert.getPubKey());
            sm2pubkey.getHexPubKey();
            System.out.println("SM2 pubKey hex: " + sm2pubkey.getHexPubKey());

            sm2PubKey = sm2pubkey.getHexPubKey();
            System.out.println("Load EncryptCert Successful");
        } else {
            System.out.println("WARN: acpsdk.encryptCert.path is empty");
        }
    }

    public static String getSm2PriKey() {
        return sm2PriKey;
    }

    public static void setSm2PriKey(String sm2PriKey) {
        CertUtilSM2.sm2PriKey = sm2PriKey;
    }

    public static String getSm2PubKey() {
        return sm2PubKey;
    }

    public static void setSm2PubKey(String sm2PubKey) {
        CertUtilSM2.sm2PubKey = sm2PubKey;
    }


}
